#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#ifdef __linux__
#include <sys/select.h>
#endif
#include <assert.h>

#include "vmalloc.h"
#include "vipc_fifo.h"

#define MKFIFO_PATH_LEN     32

struct mkfifo__
{
    int fd;
    char path[MKFIFO_PATH_LEN];
    fifo_read_func cb;
};


VFifo vFifoCreate(const char *path)
{
    struct mkfifo__ *ctx = vCalloc(1,sizeof(struct mkfifo__));
    assert(ctx);
    assert(path);

    snprintf(ctx->path,sizeof(ctx->path),"%s",path);
    int ret = mkfifo(ctx->path,S_IFIFO | 0666);
    if(ret < 0)
    {
        vFree(ctx);
        return NULL;
    }

    ctx->fd = open(ctx->path,O_RDWR);
    if(ctx->fd < 0)
    {
        vFree(ctx);
        return NULL;
    }

    ctx->cb = NULL;

    return (vFifo)ctx;
}

void vFifoDelete(vFifo vf)
{
    vFree(vf);
}

int vFifoWriteData(vFifo vf,const void *buf,size_t len)
{
    struct mkfifo__ *ctx = (struct mkfifo__*)vf;
    assert(ctx);

    return write(ctx->fd,buf,len);
}


int vFifoReadData(vFifo vf,void *buf,size_t len)
{
    struct mkfifo__ *ctx = (struct mkfifo__*)vf;
    assert(ctx);
    return read(ctx->fd,buf,len);
}
int vFifoReadDataTimeout(vFifo vf,void *buf,size_t len,unsigned long ms)
{
    struct mkfifo__ *ctx = (struct mkfifo__*)vf;
    assert(vf);

    fd_set rfd;
    FD_ZERO(&rfd);
    FD_SET(ctx->fd,&rfd);
    struct timeval tvp;
    tvp.tv_sec = ms / 1000;
    tvp.tv_usec = (ms % 1000) * 1000;

    int ret = select(ctx->fd + 1,&rfd,NULL,NULL,&tvp);
    if(ret <= 0)
        return -1;

    if(FD_ISSET(ctx->fd,&rfd))
    {
        ret = read(ctx->fd,buf,len);
    }
    return ret;
}

//监听 需要在线程中使用
typedef int (*fifo_read_func)(vFifo vf,void *buf,size_t len);
void vFifoSetReadDataCallback(vFifo vf,fifo_read_func func)
{
    struct mkfifo__ *ctx = (struct mkfifo__*)vf;
    assert(ctx);
    ctx->cb = func;
}
